using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using DA.AnimGraph;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {
    internal abstract class NodeViewInspectorSourceBase : InspectorDataSource {
        protected HandleKeeper<AGAHandle_Node> handleKeeper;

        [InspectorField(label: "node name", order: 10)]
        public RefField<string> nodeName;
        [InspectorField(tag: "addPerkButton")] public Action addPerk;
        [InspectorField(tag: "perk")] public List<AGAPerk_PerkBase> perkList;

        VisualElement perkContainer;
        protected AGEContext ageContext;
        Type nodeType;
        ListViewAGE listView;

        internal void SetHandle(AGAHandle_Node handle) {
            handleKeeper = handle.ToKeeper<AGAHandle_Node>();
            nodeType = handle.agaNodeType;
            perkList = handleKeeper.handle.GetPerks();
            if (handleKeeper.handle.data is AGANode_FunctionBase fNode) {
                nodeName = new RefField<string>(fNode.nodeName ?? "");
            }

            LoadFromModel();
        }

        protected abstract void LoadFromModel();
        protected abstract void SaveToModel();

        public override void DrawUI(VisualElement container, AGEContext ageContext, Action inspectorChangeCallback) {
            this.ageContext = ageContext;
            base.DrawUI(container, ageContext, () => {
                // 保存
                if (handleKeeper.handle.data is AGANode_FunctionBase fNode) {
                    fNode.nodeName = nodeName.value;
                }
                SaveToModel();
                inspectorChangeCallback?.Invoke();
            });
        }

        // Perk
        protected override VisualElement CustomizeField(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            if (fieldAttribute.tag == "addPerkButton") {
                return BuildAddPerkButton(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
            } else if (fieldAttribute.tag == "perk") {
                return BuildPerkInspector(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
            }
            return base.CustomizeField(name, fieldAttribute, fieldInfo, ageContext, inspectorChangeCallback);
        }

        VisualElement BuildAddPerkButton(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            var perkTypes = PerkDefine.GetAvailablePerks(nodeType);
            if (perkTypes == null) return null;
            var menuButton = new GenericDropdownButton("add perk");
            var selections = perkTypes.Select<PerkMenuItemDefine, (string, Action)>(p => (p.menuName, () => TogglePerk(p.agaPerkType))).ToArray();

            menuButton.AddMenuItem(selections);
            return menuButton;
        }

        VisualElement BuildPerkInspector(string name, InspectorFieldAttribute fieldAttribute, FieldInfo fieldInfo, AGEContext ageContext, Action inspectorChangeCallback) {
            listView = new ListViewAGE(false) {
                name = name,
                itemsSource = perkList,
            };
            listView.makeItem = () => {
                var w = new FoldoutWrapperPerk();
                w.upButtonClicked += (index) => {
                    (perkList[index], perkList[index - 1]) = (perkList[index - 1], perkList[index]);

                    listView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                w.downButtonClicked += (index) => {
                    (perkList[index], perkList[index + 1]) = (perkList[index + 1], perkList[index]);

                    listView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                w.deleteButtonClicked += (index) => {
                    perkList[index].OnDelete(ageContext);
                    if (handleKeeper.handle.TryRemovePerkByUuid(perkList[index].uuid)) {
                        listView.Rebuild();
                        inspectorChangeCallback?.Invoke();
                    }
                };
                var l = new VisualElement() {
                    name = "perk-container"
                };
                return (l, w);
            };
            listView.bindItem = (element, wrapper, index) => {
                var perk = perkList[index];
                var perkType = perk.modelProperty.GetType();
                var field = InspectorFieldFactory.SwitchField(perkType);
                if (field != null) {
                    field.Init(perkType.Name, perk.modelProperty, ageContext, inspectorChangeCallback);
                }
                element.Clear();
                element.Add(field);
                if (wrapper is FoldoutWrapperPerk w) {
                    w.index = index;
                    w.text = field.labelText;
                    w.enableUp = index > 0;
                    w.enableDown = index < perkList.Count - 1;
                    w.enableDelete = true;
                }
            };
            return listView;
        }

        /// <summary>
        /// 点一次添加
        /// </summary>
        void TogglePerk(Type perkType) {
            AddPerk(perkType);
        }

        void AddPerk(Type perkType) {
            var modelType = NodeTypeRegister.GetInstance().GetModelTypeOf(perkType);
            if (modelType == null) return;

            var model = Activator.CreateInstance(modelType) as AGAPerkModelBase;
            handleKeeper.handle.AddPerk(model, perkType);
            perkList = handleKeeper.handle.GetPerks();
            listView.itemsSource = perkList;
            listView.Rebuild();
        }
    }
}